#include "Fat12.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>


int openFile(const char* path){
  return open("data.img",O_RDONLY );
}


int readFAT12Header(struct FAT12_Header* header,const char* path){
  int ret = 0;
  int fd = openFile(path);
  if(fd <= 0){
    printf("open file failed!\n");
    return ret;
  }
  ret = read(fd,header,512);
  if(ret == 512){
    printf("open file success\n");
    ret = 0;
  }else{
    ret = -1;
    printf("read file failed\n");
  }
  close(fd);
  return ret;
}

void printFAT12Header(struct FAT12_Header* header){
  printf("BS_JmpBoot:");
  for(int i = 0; i < 3; i++){
    printf("%x",header->BS_JmpBoot[i]);
  }
  printf("\n");

  printf("BS_OEMName:");
  for(int i = 0; i < 8; i++){
    printf("%c",header->BS_OEMName[i]);
  }
  printf("\n");

  /**
  printf("BPB_BytsPerSec:");
  for(int i = 0; i < 2; i++){
    printf("%x",header->BPB_BytsPerSec[i]);
  }
  printf("\n");
  **/
  printf("BPB_BytsPerSec:%x\n",header->BPB_BytsPerSec);
  
  printf("BPB_SecPerClus:%d\n",header->BPB_SecPerClus);

  printf("BPB_RsvdSecCnt:%d\n",header->BPB_RsvdSecCnt);

  printf("BPB_NumFats:%d\n",header->BPB_NumFats);

  printf("BPB_RootEntCnt:%d\n",header->BPB_RootEntCnt);

  printf("BPB_TotSec16:%d\n",header->BPB_TotSec16);

  printf("BPB_Media:%x\n",header->BPB_Media);

  printf("BPB_FATSz16:%x\n",header->BPB_FATSz16);

  printf("BPB_SECPerTrk:%x\n",header->BPB_SECPerTrk);

  printf("BPB_NumHeads:%x\n",header->BPB_NumHeads);

  printf("BPB_HiddSec:%x\n",header->BPB_HiddSec);

  printf("BPB_ToSec32:%x\n",header->BPB_ToSec32);

  printf("BS_DrvNum:%x\n",header->BS_DrvNum);

  printf("BS_Reserved1:%x\n",header->BS_Reserved1);

  printf("BS_BootSig:%x\n",header->BS_BootSig);

  printf("BS_VOLID:%x\n",header->BS_VOLID);

  printf("BS_VOILab:");
  for(int i = 0; i < 11; i++){
    printf("%c",header->BS_VOILab[i]);
  }
  printf("\n");
  
  printf("BS_FileSysType:");
  for(int i = 0; i < 8; i++){
    printf("%c",header->BS_FileSysType[i]);
  }
  printf("\n");

  printf("BOOT_Code:");
  for(int i = 0; i < 448; i++){
    printf("%c",header->BOOT_Code[i]);
  }
  printf("\n");

  printf("END:%x\n",header->END);

}

struct FAT12_DIR* readFlatDir(const char* path, int* n){
  struct FAT12_Header header;
  int ret = readFAT12Header(&header, path);
  if(ret != 0){
    printf("Parse File header failed\n");
    return NULL;
  }
  
  //获取根目录区的大小 扇区个数 
  *n = header.BPB_RootEntCnt*sizeof(struct FAT12_DIR)/header.BPB_BytsPerSec;
  printf("Dir Sec Count:%d\n",*n);

  if(*n <= 0){
    printf("have no dir and file\n");
    return NULL;
  }
  int fd = openFile(path);
  //根目录区从第19扇区开始
  int skipBys = 19*header.BPB_BytsPerSec;
  printf("skip bytes count:%d\n",skipBys);
  
  struct FAT12_DIR* dirs;
  //根目录分配空间大小 根目录区的个数* 每一个扇区的字节数
  dirs =  malloc(*n*header.BPB_BytsPerSec);
  memset(dirs,0,*n*header.BPB_BytsPerSec); 
  lseek(fd,skipBys,SEEK_SET);
  int readBys = read(fd,dirs,*n*header.BPB_BytsPerSec);
  close(fd);
  if(readBys <= 0){
    return NULL;
  }
  return dirs;
}


struct FAT12_DIR findDirByPos(struct FAT12_Header* header,const char* path,int i){
  struct FAT12_DIR ret = {{0}};
  int fd = openFile(path);
  if(fd > 0 && (0 <= i) && (i < header->BPB_RootEntCnt)){
    lseek(fd,19*header->BPB_BytsPerSec+i*sizeof(struct FAT12_DIR), SEEK_SET);
    int readBys = read(fd,&ret,sizeof(struct FAT12_DIR));
  }
  close(fd);
  return ret;
}

struct FAT12_DIR findDirByFileName(struct FAT12_Header* header,const char* path,const char* fileName){
  struct FAT12_DIR ret = {{0}};
  for(int i = 0; i < header->BPB_RootEntCnt;  i++){
    ret = findDirByPos(header, path, i);
    char fn[11] = {0};
    strcpy(fn,fileName);
    char* dot = ".";
    char* pre = strtok(fn,dot); 
    char* next = strtok(NULL,dot);
    if(strstr(ret.Dir_Name, pre) != NULL && strstr(ret.Dir_Name, next) != NULL){
      return ret;
    }
  }
  return ret;  
}


void printFlatDir(struct FAT12_DIR* dir){
   if(dir == NULL){
      return;
   }
   //dir->Dir_Name[0xa] = 0;
   printf("Dir_Name:%s\n",dir->Dir_Name);

   printf("Dir_Attr:%c\n",dir->Dir_Attr);

   //dir->Reserve[0x09] = 0;
   printf("Reserve:%s\n",dir->Reserve);

   printf("writeTime:%d\n",dir->Dir_wrtTime);

   printf("writeDate:%d\n",dir->Dir_WrtDate);

   printf("Dir_FstClus:%d\n",dir->Dir_FstClus);

   printf("Dir_FileSize:%d\n",dir->Dir_FileSize);

   printf("\n");

}


void printAlldir(struct FAT12_Header* header,const char* path){
  for(int i = 0; i < header->BPB_RootEntCnt; i++){
     struct FAT12_DIR re = findDirByPos(header, path, i);
     if(re.Dir_Name[0] != '\0'){
        printFlatDir(&re); 
     }
  }
}

unsigned short* readFat(struct FAT12_Header* header,const char* path,int* n){
  int fd = openFile(path);
  //fat表的大小
  int size = header->BPB_BytsPerSec*9;
  //保存fat表
  unsigned char fat[size];
  //fat表项数组
  unsigned short* ret = malloc(size*2/3*sizeof(short));
  // 初始化数组为0xff 
  for(int i = 0; i < size*2/3; i++){
    ret[i] = 0xff;
  }
  //定位fat表的起始位置 第一个扇区的地方
  lseek(fd,header->BPB_BytsPerSec, SEEK_SET);
  read(fd,fat,size);
  //将fat表中的值 保存在fat表项数组里
  //内存数据方式 0x01 0x02 0x03 0x04   数值是0x04030201
  //i i+1 i+2  fat表里的字符地址 从左边到右边 高位到地位
  //j => (0x0F & fat[i+1]) <<8 | fat[i]
  //j+1=> (fat[i+1] >> 4) | (fat[i+2] << 4)
  //三个字节代表两个fat表项
  for(int i = 0,j = 0; i < size; i+=3,j+=2){
     ret[j] = (fat[i+1] & 0x0F) << 8 | fat[i];
     ret[j+1] = (0x0f&(fat[i+1] >> 4)) | (fat[i+2] << 4);
  }
  *n = size*2/3;
  close(fd);
  return ret;
}


unsigned char* readFileContent(struct FAT12_Header* header,const char* path,const char* fileName){
   struct FAT12_DIR dir = findDirByFileName(header, path, fileName);  
   int fatSize;
   char ret[dir.Dir_FileSize];
   int count = 0;
   if(dir.Dir_Name[0] != '\0'){
      unsigned short* vec = readFat(header, path, &fatSize);
      int fd = openFile(path);
      char buf[512] = {0};
      for(int i = 0, j = dir.Dir_FstClus; j < 0xFF7; i+=512,j=vec[j]){
         lseek(fd,(int)(header->BPB_BytsPerSec*(33+j-2)), SEEK_SET);
         read(fd,buf,sizeof(buf));
         for(int k = 0; k < sizeof(buf); k++){
            if(count < dir.Dir_FileSize){
                ret[i+k] = buf[k];
                count++;
            }
         }
      } 
      close(fd);
   }
   printf("read Content:%s\n",ret);
   return NULL;

}

void testReadHeader(){
   struct FAT12_Header header;
   int ret = readFAT12Header(&header, "data.img");
   printf("short size:%d\n",(int)sizeof(short));
   if(!ret){
     //printFAT12Header(&header); 
     //printAlldir(&header, "data.img");
     //struct FAT12_DIR dir = findDirByFileName(&header, "data.img","MAIN.CPP");
     //printFlatDir(&dir);
     readFileContent(&header, "data.img", "MAIN.CPP");
     //printf("find file by Name:%s\n",dir.Dir_Name);
     int n;
   }
}
void testReadDir(){
  int n;
  struct FAT12_DIR* dirs = readFlatDir("data.img", &n);
  printf("\n");
  if(n > 0){
    for(int i = 0; i < n; i++){
      printFlatDir(dirs+i);
      printf("\n");
    }
  }
}

int main(){
  testReadHeader();
  //testReadDir();
  return 0;
}
